#pragma once
#include "requestor.hpp"



/*
三个call都是不管是同步，异步，回调，都是通过下层的requstor把msg设置回来
异步：执行完成了，但是结果没有返回，目的：不阻塞当前线程的执行
*/
namespace bitrpc
{
    namespace client
    {
        class RpcCaller
        {
        public:
            using ptr = std::shared_ptr<RpcCaller>;
            /* 因为如果采用回调，那么requstor转发的msg一定是BaseMessage的，所以JsonAsyncResponse，JsonResponseCallback都要接收Json::Value的result */
            using JsonAsyncResponse = std::future<Json::Value>;
            using JsonResponseCallback = std::function<void(const Json::Value &)>;
            RpcCaller(const Requestor::ptr &requestor) : _requestor(requestor) {}

            // requestor中的处理是针对BaseMessage进行处理的
            // 用于在rpccaller中针对结果的处理是针对 RpcResponse里边的result进行的

            /* 阻塞式call */
            bool call(const BaseConnection::ptr &conn, const std::string &method,
                      const Json::Value &params, Json::Value &result)
            {   

                DLOG("开始同步rpc调用...");
                // 1. 组织请求
                auto req_msg = MessageFactory::create<RpcRequest>();
                req_msg->setId(UUID::uuid());
                req_msg->setMType(MType::REQ_RPC);
                req_msg->setMethod(method);
                req_msg->setParams(params);
                BaseMessage::ptr rsp_msg;
                // 2. 发送请求
                bool ret = _requestor->send(conn, std::dynamic_pointer_cast<BaseMessage>(req_msg), rsp_msg);
                if (ret == false)
                {
                    ELOG("同步Rpc请求失败！");
                    return false;
                }
                DLOG("收到响应，进行解析，获取结果!");
                // 3. 等待响应
                /* 这里在发起了send同步版本后，send同步版本会去调用异步版本，阻塞在send同步里的get处  */
                auto rpc_rsp_msg = std::dynamic_pointer_cast<RpcResponse>(rsp_msg);
                if (!rpc_rsp_msg)
                {
                    ELOG("rpc响应，向下类型转换失败！");
                    return false;
                }
                if (rpc_rsp_msg->rcode() != RCode::RCODE_OK)
                {
                    ELOG("rpc请求出错：%s", errReason(rpc_rsp_msg->rcode()).c_str());
                    return false;
                }
                result = rpc_rsp_msg->result();       
                                                      
                DLOG("结果设置完毕！");
                return true;
            }

            /* 对于异步来讲传智能指针非常重要，而且要传shared_ptr的智能指针，传参就是将变量的生命周期交给下一个智能指针维护 */
            bool call(const BaseConnection::ptr &conn, const std::string &method,
                      const Json::Value &params, JsonAsyncResponse &result) /* 传进来一个future，cb里设置set_value */
            {
                // 向服务器发送异步回调请求，设置回调函数，回调函数中会传入一个promise对象，在回调函数中去堆promise设置数据
                auto req_msg = MessageFactory::create<RpcRequest>();
                req_msg->setId(UUID::uuid());
                req_msg->setMType(MType::REQ_RPC);
                req_msg->setMethod(method);
                req_msg->setParams(params);

                /* 创建promise并且和result进行绑定，在回调里面利用promise设置结果给result */
                auto json_promise = std::make_shared<std::promise<Json::Value>>(); /* 如果不用智能指针，那么在return true之后，promise就会 */
                result = json_promise->get_future();                               /* 析构，此时再用result获取结果就会抛出异常  */
                Requestor::RequestCallback cb = std::bind(&RpcCaller::Callback,
                                                          this, json_promise, std::placeholders::_1);
                bool ret = _requestor->send(conn, std::dynamic_pointer_cast<BaseMessage>(req_msg), cb);
                /* 这里调用send后，会创建一个requestdescribe，cb会保存在里面，dispatcher使用onresponse会判断出
                   这个request属于callback类的，直接调用回调函数，所以json_promise会一直保存在cb里面 */
                if (ret == false)
                {
                    ELOG("异步Rpc请求失败！");
                    return false;
                }
                return true;
            }
            bool call(const BaseConnection::ptr &conn, const std::string &method,
                      const Json::Value &params, const JsonResponseCallback &cb) 
            {
                auto req_msg = MessageFactory::create<RpcRequest>();
                req_msg->setId(UUID::uuid());
                req_msg->setMType(MType::REQ_RPC);
                req_msg->setMethod(method);
                req_msg->setParams(params);

                Requestor::RequestCallback req_cb = std::bind(&RpcCaller::Callback1,
                                                              this, cb, std::placeholders::_1);
                bool ret = _requestor->send(conn, std::dynamic_pointer_cast<BaseMessage>(req_msg), req_cb);
                if (ret == false)
                {
                    ELOG("回调Rpc请求失败！");
                    return false;
                }
                return true;
            }

        private:
            void Callback1(const JsonResponseCallback &cb, const BaseMessage::ptr &msg) /* 因为 rdp->callback(msg);只接受一个参数，所以这里要bind参数 */
            {
                auto rpc_rsp_msg = std::dynamic_pointer_cast<RpcResponse>(msg);
                if (!rpc_rsp_msg)
                {
                    ELOG("rpc响应，向下类型转换失败！");
                    return;
                }
                if (rpc_rsp_msg->rcode() != RCode::RCODE_OK)
                {
                    ELOG("rpc回调请求出错：%s", errReason(rpc_rsp_msg->rcode()).c_str());
                    return;
                }
                cb(rpc_rsp_msg->result());
            }
            void Callback(std::shared_ptr<std::promise<Json::Value>> result, const BaseMessage::ptr &msg)
            {
                auto rpc_rsp_msg = std::dynamic_pointer_cast<RpcResponse>(msg);
                if (!rpc_rsp_msg)
                {
                    ELOG("rpc响应，向下类型转换失败！");
                    return;
                }
                if (rpc_rsp_msg->rcode() != RCode::RCODE_OK)
                {
                    ELOG("rpc异步请求出错：%s", errReason(rpc_rsp_msg->rcode()).c_str());
                    return;
                }
                result->set_value(rpc_rsp_msg->result());/* promise把数据设置进msg里 */
            }

        private:
            Requestor::ptr _requestor;
        };
    }
}


/*
三个bool call( 都以requestor的send为接口
第一个传Json::Value result同步，将msg里的值带出来，调用send的同步
第二个传一个future用来获取异步调用的结果，设置进promise中   JsonAsyncResponse &result  ，最后把结果设置进promise中
第三个传一个JsonResponseCallback = std::function<void(const Json::Value &)>;)  我需要Json::Value result作为参数，拿到结果了调用JsonResponseCallback


requestor中的send里面的回调是针对BaseMessage进行处理的(请求部分的BaseMessage(发送)和回复部分的BaseMessage(提取出来))
caller中的三个call，是针对所有的具象层BaseMessage结构进行处理的(请求部分创建对应的请求类似RPC_REQ，回复部分提取msq内部的result)


requestor的回调方法只需要一个msg
caller模块提供的两个回调方法(每个方法有两个参数)就是和call(异步，回调)相对应的
callback和异步对应，将callback和JsonAsyncResponse &result进行封装成回调方法提供给requstor，在外部利用result获取结果
callback1和回调对应，将callback1和const JsonResponseCallback &cb进行封装成回调方法requstor，在执行回调方法的时候执行cb(cb需要一个Json::Value为参数)
*/

/* requestor负责对响应的处理，获取muduo send异步调用结果，(选择直接设置响应msg还是调用设置的cb)，和提供发送方式的选择(3个send) 
   rpc_caller的三个call方法，第一个call选择调用同步的send，一直等到send结束再去处理msg，在返回bool和结果
   第二个和第三个call是选择调用回调的send，直接返回处理的bool，等到requestor调用回调再去处理msg，获得结果
*/